#include "polygon.hpp"
#include "pattern.hpp"
#include "load.h"
#include <cstdio>

int get_int(const char *buf, int &i) {
    char ch = buf[i++];
    int x = 0;
    bool neg_flag = false;
    if (ch == '-') {
        neg_flag = true;
        ch = buf[i++];
    }
    while (ch >= '0' && ch <= '9') {
        x = x * 10 + ch - '0';
        ch = buf[i++];
    }
    if (neg_flag)
        x = -x;
    return x;
}

Point get_point(char *buf, int &i) {
    i++; //吞掉左括号
    int x = get_int(buf, i); //会吞掉逗号
    int y = get_int(buf, i); //会吞掉右括号
    return {x, y};
}

//输入
Polygon get_polygon(char *buf, int &i) {
    Polygon p;
    p.add_node(get_point(buf, i)); // 加入第一个点
    char ch = buf[i++];
    while (ch == ',') {
        p.add_node(get_point(buf, i));
        ch = buf[i++];
    }
    i--;
    p.init_area();
    p.sort_nodes();
    return p;
}

void get_polygon(char *buf, int &i, vector<Polygon> *temp) {
    temp->emplace_back();
    temp->back().add_node(get_point(buf, i)); // 加入第一个点
    char ch = buf[i++];
    while (ch == ',') {
        temp->back().add_node(get_point(buf, i));
        ch = buf[i++];
    }
    i--;
    temp->back().init_area();
    temp->back().sort_nodes();
}

void get_layout(const char *filename, vector<Polygon> &ps, int thread_cnt) {
    // 读取文件大小
    FILE *f = fopen(filename, "rb");
    fpos_t fpos;
    fgetpos(f, &fpos);
    fseek(f, 0, SEEK_END);
    int file_size = ftell(f);
    fsetpos(f,&fpos);
    char *buf = (char*) malloc(sizeof (char) * (file_size + 2333));
    FILE *fs[64];
    int seg_sz = file_size / thread_cnt + 1;
    int head[64], rear[64];
    if (thread_cnt <= 1) {
        fread(buf, 1, file_size, f);
    } else {
        for (int i = 0; i < thread_cnt; i++) {
            head[i] = i * seg_sz;
            rear[i] = (i + 1) * seg_sz;
        }
        rear[thread_cnt - 1] = file_size;
        fs[0] = f;
        for (int i = 1; i < thread_cnt; i++) {
            fs[i] = fopen(filename, "rb");
            fseek(fs[i], head[i], 0);
        }
#pragma omp parallel for num_threads(thread_cnt)
        for (int i = 0; i < thread_cnt; i++) {
            fread(buf + head[i], 1, rear[i] - head[i], fs[i]);
        }
    }
    ps.reserve(3000000);
    if (thread_cnt <= 1) {
        int i = 0;
        char ch = buf[i++];
        while (ch == '(') {
            i--;
            get_polygon(buf, i, &ps);
            ch = buf[i++]; // 吞换行
            if(i == file_size) return;
            ch = buf[i++]; // 读左括号
            if(i == file_size) return;
        }
    } else {
        for (int i = 0; i < thread_cnt - 1; i++) {
            while (buf[rear[i]] != '\n') {
                rear[i]++;
                head[i + 1] ++;
            }
            rear[i]++;
            head[i + 1]++;
        }
        vector<vector<Polygon>*> polygons;
        polygons.reserve(thread_cnt);
        for (int i = 0; i < thread_cnt; i++) {
            polygons.push_back(new vector<Polygon>);
            if (i > 0) {
                polygons[i]->reserve(500000);
            }
        }
        polygons[0] = &ps;
#pragma omp parallel for num_threads(thread_cnt)
        for (int t = 0; t < thread_cnt; t++) {
            int i = head[t];
            char ch = buf[i++];
            while (ch == '(') {
                i--;
                get_polygon(buf, i, polygons[t]);
                ch = buf[i++]; // 吞换行
                if(i == file_size || i >= rear[t]) break;
                ch = buf[i++]; // 读左括号
                if(i == file_size || i >= rear[t]) break;
            }
        }
        int sum = (int) ps.size();
        for (int i = 1; i < thread_cnt; i++) {
            sum += (int) polygons[i]->size();
        }
        ps.reserve(sum);
        for (int i = 1; i < thread_cnt; i++) {
            ps.insert(ps.end(), make_move_iterator(polygons[i]->begin()), make_move_iterator(polygons[i]->end()));
            delete polygons[i];
        }
    }
    if (thread_cnt <= 1) {
        fclose(f);
    } else {
        for (int i = 0; i < thread_cnt; i++) {
            fclose(fs[i]);
        }
    }
    free(buf);
}

Pattern get_pattern(FILE *f) {
    // 读取文件大小
    fpos_t fpos;
    fgetpos(f, &fpos);
    fseek(f, 0, SEEK_END);
    unsigned int file_size = ftell(f);
    fsetpos(f,&fpos);
    char *buf = (char*) malloc(sizeof (char) * (file_size + 2333));
    fread(buf, 1, file_size, f);
    vector<Polygon> nodes;
    int i = 0;
    char ch = buf[i++];
    while (ch != ':') { //吞掉前导字符串
        ch = buf[i++];
    }
    ch = buf[i++]; //吞换行
    ch = buf[i++]; //识别左括号
    while (ch == '(') {
        i--;
        nodes.push_back(move(get_polygon(buf, i)));
        ch = buf[i++]; // 吞换行
        ch = buf[i++]; // 读左括号
        if(ch == '['){
            nodes[nodes.size() - 1].merge(get_polygon(buf, i));
            ch = buf[i++]; // 吞]
            ch = buf[i++]; // 吞换行
            ch = buf[i++]; // 读左括号
        }
    }
    while (ch != ':') { //吞掉前导字符串
        ch = buf[i++];
    }
    ch = buf[i++]; //吞掉换行
    Point left_bottom = get_point(buf, i);
    ch = buf[i++]; //吞掉逗号
    Point right_bottom = get_point(buf, i);
    ch = buf[i++]; //吞掉逗号
    Point right_top = get_point(buf, i);
    ch = buf[i++]; //吞掉逗号
    Point left_top = get_point(buf, i);
    //Pattern p = Pattern(nodes, right_top.get_x(), right_top.get_y());
    //如果left_bottom不是(0,0),那么需要进行点的平移
    Pattern p = Pattern(nodes, right_top.get_x() - left_bottom.get_x(), right_top.get_y() - left_bottom.get_y());
    p.set_left_node(left_bottom);
    p.normalization();
    //将左下角移动到(0,0)
    p.set_left_node(Point(0, 0));

    p.find_nb_polygon();
    //p.sort_polygon();
    free(buf);
    return p;
}
